package com.fortune.cat.service;

import com.fortune.cat.bean.RouteDefinitionRecipient;
import com.fortune.cat.constant.ZkPathConstants;
import com.fortune.cat.convert.RouteConverts;
import com.fortune.cat.jooq.tables.TbPredicateDefinitionRecipient;
import com.fortune.cat.jooq.tables.TbRouteDefinitionRecipient;
import com.fortune.cat.jooq.tables.pojos.TbFilterDefinitionRecipient;
import lombok.extern.slf4j.Slf4j;
import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.lang3.StringUtils;
import org.jooq.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * @author zhaozeyang
 * @date 2019/4/17 17:33
 * @description
 */
@Service
@Slf4j
public class RouteDefinitionService {

    private final DSLContext dsl;

    private final ZkClient zkClient;

    TbRouteDefinitionRecipient tbRoute = TbRouteDefinitionRecipient.TB_ROUTE_DEFINITION_RECIPIENT;

    TbPredicateDefinitionRecipient tbPredicate = TbPredicateDefinitionRecipient.TB_PREDICATE_DEFINITION_RECIPIENT;

    com.fortune.cat.jooq.tables.TbFilterDefinitionRecipient tbFilter = com.fortune.cat.jooq.tables.TbFilterDefinitionRecipient.TB_FILTER_DEFINITION_RECIPIENT;

    public RouteDefinitionService(DSLContext dsl, ZkClient zkClient) {
        this.dsl = dsl;
        this.zkClient = zkClient;
    }

    @Transactional(rollbackFor = Exception.class)
    public RouteDefinitionRecipient createOrUpdate(RouteDefinitionRecipient recipient) {
        //入库
        com.fortune.cat.jooq.tables.pojos.TbRouteDefinitionRecipient route = RouteConverts.convertRoute(recipient);
        List<TbFilterDefinitionRecipient> filters = RouteConverts.convertFilter(recipient.getFilters());
        List<com.fortune.cat.jooq.tables.pojos.TbPredicateDefinitionRecipient> predicates = RouteConverts.convertPredicate(recipient.getPredicates());
        if (Objects.isNull(route.getId())) {
            route.setUpdator(route.getCreator());
            //路由主表
            dsl.insertInto(tbRoute)
                    .columns(tbRoute.ROUTE_ID, tbRoute.URI, tbRoute.ORDER, tbRoute.CREATOR, tbRoute.UPDATOR)
                    .values(route.getRouteId(), route.getUri(), route.getOrder(), route.getCreator(), route.getUpdator())
                    .execute();
        } else {
            dsl.update(tbRoute)
                    .set(tbRoute.ROUTE_ID, route.getRouteId())
                    .set(tbRoute.ORDER, route.getOrder())
                    .set(tbRoute.URI, route.getUri())
                    .set(tbRoute.UPDATOR, UserService.currentUserId())
                    .where(tbRoute.ID.eq(route.getId()))
                    .execute();
            dsl.delete(tbFilter)
                    .where(tbFilter.ROUTE_ID.eq(route.getRouteId()))
                    .execute();
            dsl.delete(tbPredicate)
                    .where(tbPredicate.ROUTE_ID.eq(route.getRouteId()))
                    .execute();
        }
        //过滤器
        InsertValuesStep8 step = dsl.insertInto(tbFilter)
                .columns(tbFilter.ROUTE_ID, tbFilter.ARGS, tbFilter.NAME, tbFilter.EXTERNAL, tbFilter.EXTERNAL_NAME, tbFilter.URL, tbFilter.CREATOR, tbFilter.UPDATOR);
        filters.forEach(filter -> step.values(filter.getRouteId(), filter.getArgs(), filter.getName(), filter.getExternal(), filter.getExternalName(), filter.getUrl(), UserService.currentUserId(), UserService.currentUserId()));
        step.execute();
        InsertValuesStep5 step5 = dsl.insertInto(tbPredicate)
                .columns(tbPredicate.ROUTE_ID, tbPredicate.ARGS, tbPredicate.NAME, tbPredicate.CREATOR, tbPredicate.UPDATOR);
        predicates.forEach(predicate -> step5.values(predicate.getRouteId(), predicate.getArgs(), predicate.getName(), UserService.currentUserId(), UserService.currentUserId()));
        step5.execute();
        String routePath = ZkPathConstants.buildRoutePath(recipient.getRouteId());
        if (!zkClient.exists(routePath)) {
            zkClient.createPersistent(routePath, true);
        }
        //入zk
        zkClient.writeData(routePath, recipient);
        //修改字节点数据开启通知
        zkClient.writeData(ZkPathConstants.ROUTE_DEFINITION, ZkPathConstants.parentRouteData());
        return recipient;
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteRoute(Long id) {
        Result<Record1<String>> result = dsl.select(tbRoute.ROUTE_ID).from(tbRoute).where(tbRoute.ID.eq(id)).fetch();
        dsl.delete(tbRoute).where(tbRoute.ID.eq(id));
        dsl.delete(tbPredicate).where(tbPredicate.ROUTE_ID.eq(result.get(0).value1()));
        dsl.delete(tbFilter).where(tbFilter.ROUTE_ID.eq(result.get(0).value1()));
    }

    public List<RouteDefinitionRecipient> getRoute(String routeName, Integer page, Integer number) {
        SelectJoinStep step = dsl.select()
                .from(tbRoute);
        if (StringUtils.isNotBlank(routeName)) {
            step.where(tbRoute.ROUTE_ID.eq(routeName));
        }
        List<com.fortune.cat.jooq.tables.pojos.TbRouteDefinitionRecipient> list =
                step.limit(number)
                        .offset(page)
                        .fetch()
                        .into(com.fortune.cat.jooq.tables.pojos.TbRouteDefinitionRecipient.class);

        return RouteConverts.convertRouteRecipient(list);
    }

    public RouteDefinitionRecipient getRoute(String routeName) {
        RouteDefinitionRecipient routeDefinitionRecipient = RouteConverts.convertRouteRecipient(dsl.select().from(tbRoute)
                .where(tbRoute.ROUTE_ID.eq(routeName))
                .fetch()
                .into(com.fortune.cat.jooq.tables.pojos.TbRouteDefinitionRecipient.class).get(0));
        routeDefinitionRecipient.setFilters(RouteConverts.convertFilterRecipient(dsl.select().from(tbFilter)
                .where(tbFilter.ROUTE_ID.eq(routeName))
                .fetch()
                .into(com.fortune.cat.jooq.tables.pojos.TbFilterDefinitionRecipient.class)));
        routeDefinitionRecipient.setPredicates(RouteConverts.convertPredicateRecipient(dsl.select().from(tbPredicate)
                .where(tbPredicate.ROUTE_ID.eq(routeName))
                .fetch()
                .into(com.fortune.cat.jooq.tables.pojos.TbPredicateDefinitionRecipient.class)));
        return routeDefinitionRecipient;
    }
}
